﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using __ts.Core.Package;
using SevenZip;

namespace CCU.Update
{
    public partial class SetupPackage : Form
    {
        /// <summary>
        /// 解压前执行的文件
        /// </summary>
        private static string extractBeforeFile = "extractBefore.bat";
        /// <summary>
        /// 解压后执行的文件
        /// </summary>
        private static string extractAfterFile = "extractAfter.bat";
        /// <summary>
        /// 配置文件
        /// </summary>
        private static string configFile = "package.xml";
        /// <summary>
        /// 更新包
        /// </summary>
        private PackageInfo package { get; set; }
        /// <summary>
        /// 解压路径集合
        /// </summary>
        private Hashtable extractpaths { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="package"></param>
        public SetupPackage(PackageInfo package)
        {
            InitializeComponent();
            this.package = package;
            extractpaths = new Hashtable();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        public void WriteLog(String str)
        {
            String upfilepath = package.PackageSaveDirectory + "update.log";

            if (!Directory.Exists(package.PackageSaveDirectory))
                Directory.CreateDirectory(package.PackageSaveDirectory);

            FileStream fs = new FileStream(upfilepath, FileMode.Append, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fs);
            streamWriter.BaseStream.Seek(0, SeekOrigin.End);
            streamWriter.WriteLine(str);
            streamWriter.Flush();
            streamWriter.Close();
            fs.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        private void readConfig()
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(package.PackageSaveDirectory + configFile);
            XmlNodeList nodes = doc.SelectNodes("packageConfigs/extractpath/*");
            if (nodes.Count > 0)
            {
                foreach (XmlNode node in nodes)
                {
                    extractpaths.Add(node.Name, node.InnerText);
                }
            }
        }

        /// <summary>
        /// 显示提示内容
        /// </summary>
        /// <param name="str"></param>
        private void ShowTip(String str)
        {
            this.listBox1.Items.Add(str);
            this.listBox1.SelectedIndex = this.listBox1.Items.Count - 1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool Setup()
        {
            if (!File.Exists(package.PackageSaveDirectory + package.PackageFile))
            {
                ShowTip(DateTime.Now.ToString() + ": can't find the local package.");
                return false;
            }

            ShowTip(DateTime.Now.ToString() + ": extracting package config file with secret key.");
            // 解压package的配置文件
            FileStream fs = new FileStream(package.PackageSaveDirectory + configFile, FileMode.Create, FileAccess.ReadWrite);
            //SevenZipExtractor sZip = new SevenZipExtractor(package.PackageSaveDirectory + package.PackageFile, extractKey);
            SevenZipExtractor sZip = new PackageExtractor().SevenZipExtractor(package.PackageSaveDirectory + package.PackageFile);
            sZip.ExtractFile(configFile, fs);
            fs.Flush();
            fs.Dispose();

            ShowTip(DateTime.Now.ToString() + ": extract config file successful, reading config.");
            // 读取配置文件
            readConfig();

            if (extractpaths.Count > 0)
            {
                ShowTip(DateTime.Now.ToString() + ": read config successful.");
                int bi = sZip.ArchiveFileNames.IndexOf(extractBeforeFile);
                if (bi > -1)
                {
                    ShowTip(DateTime.Now.ToString() + ": execute extractBefore.bat");
                    // 执行extractBefore.bat
                    sZip.ExtractFiles(package.PackageSaveDirectory, bi);
                    executeBat(extractBeforeFile);
                }

                ShowTip(DateTime.Now.ToString() + ": extracting files.");
                // 按照配置的解压路径解压文件
                for (int i = 0; i < sZip.ArchiveFileData.Count; i++)
                {
                    ArchiveFileInfo arch = sZip.ArchiveFileData[i];
                    int t = arch.FileName.IndexOf("\\");
                    if (t != -1)
                    {
                        string _oldFolderName, _extractPDir, _extractPath, _extractDir;
                        _oldFolderName = arch.FileName.Substring(0, t);
                        _extractPDir = extractpaths[_oldFolderName].ToString();
                        _extractPath = _extractPDir + arch.FileName.Substring(_oldFolderName.Length, arch.FileName.Length - _oldFolderName.Length);
                        _extractDir = Path.GetDirectoryName(_extractPath);

                        if (!Directory.Exists(_extractDir))
                            Directory.CreateDirectory(_extractDir);

                        if (!arch.IsDirectory)
                            sZip.ExtractFile(arch.Index, File.Create(_extractPath));

                        ShowTip(DateTime.Now.ToString() + ": extract file to " + _extractPath);
                    }
                    else
                    {
                        sZip.ExtractFiles(package.PackageSaveDirectory, arch.Index);
                        ShowTip(DateTime.Now.ToString() + ": extract file to " + package.PackageSaveDirectory + arch.FileName);
                    }
                }

                // 执行extractAfter.bat
                if (File.Exists(package.PackageSaveDirectory+extractAfterFile))
                {
                    ShowTip(DateTime.Now.ToString() + ": execute extractAfter.bat");
                    executeBat(extractAfterFile);
                }

                buildLog();
            }
            else
            {
                ShowTip(DateTime.Now.ToString() + ": can't read config.");
            }

            sZip.Dispose();
            return true;
        }

        private void executeBat(string file)
        {
            Process p = new Process();
            p.StartInfo.FileName = package.PackageSaveDirectory + file;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();

            System.IO.StreamReader sr = p.StandardOutput;
            string s = string.Empty;
            while ((s = sr.ReadLine()) != null)
            {
                ShowTip(DateTime.Now.ToString() + ": " + s);
            }
            p.WaitForExit();
            p.Dispose();
        }

        private void buildLog()
        {
            foreach (object obj in this.listBox1.Items)
                package.LogBuilder.Append(obj).Append("\r\n");
        }

        private void SetupPackage_Load(object sender, EventArgs e)
        {
            this.backgroundWorker_UpDate.RunWorkerAsync();
        }

        private void backgroundWorker_UpDate_DoWork(object sender, DoWorkEventArgs e)
        {
            bool flag = this.Setup();
            ShowTip(DateTime.Now.ToString() + ": setup successful. you can close this window.");
            if (package.AutoRun)
                this.Close();
        }
    }
}
